/**
 * 微服务认证授权模块
 * @author lms 2022.08.11
 */
package ms.core.gateway.utils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import lombok.Data;
import ms.core.tool.DateTimeTool;
import ms.core.tool.EncryptTool;
import ms.core.tool.JsonTool;
import ms.core.tool.Log4j2Tool;
import ms.core.tool.StreamTool;

public class LWGUtils {
	private static String ONLINE  = "微服务已在线";
	private static String OFFLINE = "微服务未上线";

	private static String fileName = "/config/LWGClient.xml";
	private static Map<String, LWGClient> clients = new HashMap<>();

	/**
	 * 加载微服务配置文件
	 */
	public static void init() {
		try{
			InputStream in = StreamTool.loadFileToStream(LWGUtils.class, fileName);
			SAXReader reader = new SAXReader();
			Document doc = reader.read(in);
			Element root = doc.getRootElement();
			List<Element> items = root.elements();
			for(Element item : items){
				LWGClient cli = new LWGClient();
				cli.setClientId(item.attributeValue("clientId"));
				cli.setSecretKey(item.attributeValue("secretKey"));
				cli.setDesc(item.attributeValue("desc"));
				cli.setOnline(OFFLINE);
				clients.put(cli.getClientId(), cli);
			}
			in.close();
		} catch (Exception e) {
			Log4j2Tool.error(LWGUtils.class, e);
		}
	}
	
	private static synchronized void checkOnline(LWGClient client) {
		if (client.getServs()!=null && client.getServs().size()>0) {
			// 检查握手是否超期
			int i=0;
			while (i<client.getServs().size()) {
				long seconds = DateTimeTool.secondsBetween(new Date(), client.getServs().get(i).shakehand);
				if (seconds>10)
					client.getServs().remove(i);
				else
					i++;
			}
		}
		boolean online = (client.getServs()!=null && client.getServs().size()>0);
		client.setOnline(online ? ONLINE : OFFLINE);
	}

	/**
	 * 按clientId获取 LWGClient
	 * 说明:在获取微服务前，需要先回收未在线的微服务
	 * 
	 * @param clientId
	 * @return null 或者克隆的LWGClient对象
	 */
	public static synchronized LWGClient getLWGClient(String clientId) {
		LWGClient client = clients.get(clientId);
		if (client==null) return null;

		checkOnline(client);
		return JsonTool.objectToBean(client, LWGClient.class);
	}
	
	/**
	 * 获取已注册微服务
	 * 
	 * @return
	 */
	public static synchronized List<LWGClient> getLWGClientList() {
		List<LWGClient> rets = new ArrayList<>();
		for(Map.Entry<String, LWGClient> entry: clients.entrySet()) {
			LWGClient clone = JsonTool.objectToBean(entry.getValue(), LWGClient.class);
			checkOnline(clone);
			rets.add(clone);
		}

		return rets;
	}

	/**
	 * 注册微服务
	 */
	public static synchronized void registerService(String clientId, String serviceUrl) {
		LWGClient client = clients.get(clientId);
		if (client==null) return;

		client.registerService(serviceUrl);
		client.setOnline(ONLINE);			
	}

	/**
	 * 注销微服务
	 */
	public static synchronized void unregisterService(String clientId, String serviceUrl) {
		LWGClient client = clients.get(clientId);
		if (client==null) return;

		client.unregisterService(serviceUrl);
		if (client.getServs()==null || client.getServs().size()==0)
			client.setOnline(OFFLINE);
		else
			client.setOnline(ONLINE);
	}

	@Data
	public static class LWGClient{
		private String clientId;		// 配置值
		private String secretKey;		// 配置值
		private String desc;			// 服务描述
		private List<Server> servs;		// 服务列表(同应用可部署多实例，做负载均衡)
		private String online;			// 服务是否在线说明
		
		public String getSignature(long t) {
			return EncryptTool.sha256(clientId+"~"+secretKey+"-"+t);
		}
		
		public void registerService(String serviceUrl) {
			if (servs==null) servs = new ArrayList<>();

			Server svr = null;
			for(int i=0; i<servs.size(); i++) {
				if (servs.get(i).getUrl().equalsIgnoreCase(serviceUrl)) {
					svr = servs.get(i);
					break;
				}
			}
			
			if (svr==null) {
				svr = new Server();
				svr.setUrl(serviceUrl);
				svr.setShakehand(new Date());
				servs.add(svr);
			} else {
				svr.setShakehand(new Date());
			}
		}
		
		public void unregisterService(String serviceUrl) {
			if (servs==null) return;

			for(int i=0; i<servs.size(); i++) {
				if (servs.get(i).getUrl().equalsIgnoreCase(serviceUrl)) {
					servs.remove(i);
					break;
				}
			}
		}

		@Data
		public static class Server {
			private String url;			// 微服务地址
			private Date shakehand;		// 最后会话时间:微服务->网关
		}
	}
}
